<?php
namespace App\Common\ScarecrowProvider;

/**
 * 行为日志操作表
 * Class AllHandleLog
 * @package app\common\api
 */
class ScarecrowDoLogProvider {
    private $logTableName = "sc_do_handle_logs";
    private $logFileDirName = "";
    //所有需要写入日志的列表
    private $allLog = [];
    private $logFilePath = '';
    private $isWriteFile = false;

    //操作日志类
    private static $obj='';

    protected function __construct()
    {
		//禁止new此函数
        $this->logFileDirName = 'logs/corelog';
        if (env('ACTION_LOG_WRITE_TYPE', 'mysql') == 'file') {
            $this->logFileDirName = storage_path($this->logFileDirName);
            if ($this->createFileDir($this->logFileDirName)) {
                $this->logFilePath = $this->logFileDirName . '/alldohandle_' . date("Y-m-d") . '.log';
                $this->isWriteFile = true;
            } else {
                throw new \Exception("创建日志目录失败");
            }
        }
    }

    protected function createFileDir($path) {
        if (is_dir($path)) {
            return true;
        }
        @mkdir($path, 666, true);
        return is_dir($path);
    }

	/**
	 * 获取操作日志实例类
	 * @return ScarecrowDoLogProvider|string
	 * @throws \Exception
	 */
    public static function getExample() {
        if (self::$obj) {
            return self::$obj;
        } else {
            self::$obj = new self();
            return self::$obj;
        }
    }

    /**
     * 添加一条APP日志记录
     * @param $type 操作类型 u/d/i
     * @param $data 操作数据
     * @param string $remark 操作备注
     * @param string $method 操作的方法
     */
    public function addLog($type, $data, $remark='',$token='',$method = '') {
		$remark = addslashes($remark);
        $method = empty($method) ? $this->getMethod() : $method;
        $data = addslashes(serialize($data));
        $type = !empty($type) ? $type : 'n';
        $token = $token ? : (defined('APP_USER_TOKEN') ? APP_USER_TOKEN : '');
        $userInfoObj = \App\Models\AuthManage\LoginModel::getUserInfo($token);
        if ($userInfoObj['code'] == 0) {
            $userInfo = $userInfoObj['data'];
            $userId = $userInfo['id'];
            $userName = $userInfo['nike_name'];
        } else {
            $userId = 0;
            $userName = "";
        }
        $baseIp = $this->getClientIp();
        $ip = $this->isWriteFile ? $baseIp : ip2long($baseIp);
        $route = request()->url();
        $times = time();
        $remark = "用户 " . $userName . " [{$baseIp} ". date("Y-m-d H:i:s", $times) ."]:" . $remark;
        $src = 1;
        $this->allLog[] = [
            'user_id'   =>  $userId,
            'type'      =>  $type,
            'method'    =>  $this->isWriteFile ? $method : addslashes($method),
            'data'      =>  $data,
            'remark'    =>  $remark,
            'ip'        =>  $ip,
            'route'        =>  $route,
            'created_at'=>  $this->isWriteFile ? date("Y-m-d H:i:s", $times) : $times,
            'src'       =>  $src,
        ];
    }


    /**
     * 获取上一个方法名称
     * @return string
     */
    private function getMethod() {
        $backList = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
        $backObj = isset($backList[2]) ? $backList[2] : false;
        if ($backObj) {
            $method = (isset($backObj['class']) ? $backObj['class'] : $backObj['file']) . (isset($backObj['type']) ? $backObj['type'] : '::')  . (isset($backObj['function']) ? $backObj['function'] : '');
        } else {
            $method = '';
        }
        return $method;
    }

    /**
     * 获取客户端IP
     * @return bool
     */
    private function getClientIp() {
        $ip=FALSE;
        //客户端IP 或 NONE
        if(!empty($_SERVER["HTTP_CLIENT_IP"])){
            $ip = $_SERVER["HTTP_CLIENT_IP"];
        }

        //多重代理服务器下的客户端真实IP地址（可能伪造）,如果没有使用代理，此字段为空
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
            if ($ip) { array_unshift($ips, $ip); $ip = FALSE; }
            for ($i = 0; $i < count($ips); $i++) {
                if (!preg_match ("/^(10|172.16|192.168)./", $ips[$i])) {
                    $ip = $ips[$i];
                    break;
                }
            }
        }

        //客户端IP 或 (最后一个)代理服务器 IP
        return ($ip ? $ip : $_SERVER['REMOTE_ADDR'] ?? "");
    }

    /**
     * 将数据日志写入数据库
     * @return bool
     */
    private function writeLog() {
        if (empty($this->allLog)) {
            return true;
        }

        $sql = "INSERT INTO {$this->logTableName}(`user_id`,`type`,`method`,`data`,`remark`,`ip`,`route`,`created_at`,`src`) VALUES ";

        foreach ($this->allLog as $item) {
            $sql .= ArrToSql($item) . ",";
        }
        $sql = rtrim($sql, ',');
        \Illuminate\Support\Facades\DB::insert($sql);
    }

    /**
     * 写入日志到文件
     * @return bool
     */
    private function writeLogToFile() {
        if (empty($this->allLog)) {
            return true;
        }
        $fileOBj = fopen($this->logFilePath, 'a+');

        foreach ($this->allLog as $item) {
            $str = '['.$item['created_at']." ".$item['ip'] .']: USER_ID=>'.$item['user_id'] . '; | TYPE=>'.$item['type'] . '; | METHOD=>' . $item['method'] . '; | DATA=>' . $item['data'] . ';' . PHP_EOL;
            fwrite($fileOBj, $str);
        }
        fclose($fileOBj);
        return true;
    }

    public function __destruct()
    {
        if ($this->isWriteFile) {
            $this->writeLogToFile();
        } else {
            $this->writeLog();
        }
    }
}